package com.github.gaojh.ioc.bean;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.github.gaojh.ioc.IocUtil;
import com.github.gaojh.ioc.annotation.Autowired;
import com.github.gaojh.ioc.annotation.Configuration;

import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author gaojh
 * @since 2020/3/23
 */
public class BeanInitializer extends AbstractInitializer {

    @Override
    public void doInit(ClassScanner classScanner) throws Exception {
        initBeans(classScanner);
    }

    private void initBeans(ClassScanner classScanner) throws Exception {
        List<ClassInfo> classInfos = classScanner.getAllClass();
        List<ClassInfo> nonConfigBeanList = classInfos.stream().filter(classInfo -> !classInfo.isConfigurationBean()).collect(Collectors.toList());

        //先实例化所有的bean，不包括@Bean注解的
        for (ClassInfo classInfo : nonConfigBeanList) {
            createBean(classInfo.getBeanClass());
        }

        //注入@Configuration的@Autowried的field
        List<ClassInfo> configedBeanList = classInfos.stream().filter(classInfo -> classInfo.getBeanClass().isAnnotationPresent(Configuration.class)).collect(Collectors.toList());
        for (ClassInfo classInfo : configedBeanList) {
            Object object = IocUtil.getBean(classInfo.getBeanName());
            for (Field field : classInfo.getBeanClass().getDeclaredFields()) {
                if (field.isAnnotationPresent(Autowired.class)) {
                    Autowired autowired = field.getAnnotation(Autowired.class);
                    String fieldName = StrUtil.isBlank(autowired.value()) ? classScanner.getBeanName(field.getType()) : autowired.value();
                    Object fieldObject = IocUtil.getBean(fieldName);
                    ReflectUtil.setFieldValue(object, field, fieldObject);
                }
            }
        }

        List<ClassInfo> beanClassList = classInfos.stream().filter(ClassInfo::isConfigurationBean).collect(Collectors.toList());
        for (ClassInfo classInfo : beanClassList) {
            createBean(classInfo);
        }

    }

}
